package org.abettor.util.encoding;

/**
 * 7Bit编码解码工具
 * @author <a href="http://www.abettor.org/" target="_blank">abettor</a>
 *
 */
public abstract class Encoding7Bit
{
	/**
	 * 7Bit编码（不包含扩展ASCII码部分）
	 * @param src 编码前的数据
	 * @return 执行失败返回null，否则返回编码后的数据
	 */
	public static byte[] encode(byte[] src)
	{
		//	如果传入空数据则直接返回null
		if(src == null || src.length == 0)
		{
			return null;
		}

		//	计算编码后的长度
		int dstLen = src.length * 7 / 8;
		if(src.length * 7 % 8 > 0)
		{
			dstLen ++;
		}

		//	以8byte为一组，逐组编码
		byte[] dst = new byte[dstLen];
		int srcPos = 0;
		int dstPos = 0;
		while(src.length - srcPos >= 8)
		{
			for(int i = 0; i < 7; i ++)
			{
				dst[dstPos + i] = (byte) ((src[srcPos + i] >>> i) & 0xFF);
				dst[dstPos + i] += (src[srcPos + i + 1] << (7 - i)) & 0xFF;
			}

			srcPos += 8;
			dstPos += 7;
		}

		//	将剩余部分另行编码
		for(int j = 0; j < dst.length - dstPos; j ++)
		{
			dst[dstPos + j] = (byte) ((src[srcPos + j] >>> j) & 0xFF);
			if(srcPos + j + 1 < src.length)
			{
				dst[dstPos + j] += (src[srcPos + j + 1] << (7 - j)) & 0xFF;
			}
		}

		return dst;
	}

	/**
	 * 7Bit解码
	 * @param src 解码前的数据
	 * @return 执行失败返回null，否则返回解码后的数据
	 */
	public static byte[] decode(byte[] src)
	{
		//	如果传入空数据则直接返回null
		if(src == null || src.length == 0)
		{
			return null;
		}

		//	计算解码后的长度
		int dstLen = src.length * 8 / 7;
		byte[] dst = new byte[dstLen];

		//	以7byte为一组，逐组解码
		int srcPos = 0;
		int dstPos = 0;
		while(src.length - srcPos >= 7)
		{
			for(int i = 0; i < 8; i ++)
			{
				dst[dstPos + i] = (byte) (((src[srcPos + i] << (i + 1)) & 0xFF) >>> 1);
				if(srcPos + i - 1 >= 0)
				{
					dst[dstPos + i] += ((src[srcPos + i - 1] & 0xFF) >>> (8 - i)) & 0xFF;
				}
			}

			srcPos += 7;
			dstPos += 8;
		}

		//	将剩余部分另行解码
		for(int j = 0; j < dst.length - dstPos; j ++)
		{
			dst[dstPos + j] = 0;
			if(srcPos + j - 1 >= 0)
			{
				dst[dstPos + j] += ((src[srcPos + j - 1] & 0xFF) >>> (8 - j)) & 0xFF;
			}

			if(srcPos + j < src.length)
			{
				dst[dstPos + j] += (byte) (((src[srcPos + j] << (j + 1)) & 0xFF) >>> 1);
			}
		}

		return dst;
	}
}
